/**
 * Copyright (c) 2018 开源 All rights reserved.
 * <p>
 * https://www.chengcang.com
 * <p>
 * 版权所有，侵权必究！
 */

package com.chengcang.api.modules.login.controller;


import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.chengcang.api.common.annotation.Login;
import com.chengcang.api.common.annotation.RateLimit;
import com.chengcang.api.modules.log.entity.SysLogLoginEntity;
import com.chengcang.api.modules.log.enums.LoginOperationEnum;
import com.chengcang.api.modules.log.enums.LoginStatusEnum;
import com.chengcang.api.modules.log.service.SysLogLoginService;
import com.chengcang.api.modules.login.dto.LoginDTO;
import com.chengcang.api.modules.login.dto.MobileCodeDTO;
import com.chengcang.api.modules.login.dto.RsetPwdDTO;
import com.chengcang.api.modules.login.utils.SmsUtil;
import com.chengcang.api.modules.login.utils.UserHolder;
import com.chengcang.api.modules.sys.dto.PasswordDTO;
import com.chengcang.api.modules.sys.dto.SysUserDTO;
import com.chengcang.api.modules.sys.entity.UserTenant;
import com.chengcang.api.modules.sys.service.CaptchaService;
import com.chengcang.api.modules.sys.service.SysUserService;
import com.chengcang.api.modules.sys.service.SysUserTenantService;
import com.chengcang.api.modules.sys.service.SysUserTokenService;
import com.chengcang.common.constant.RedisConstant;
import com.chengcang.common.enums.UserTenantStatusEnum;
import com.chengcang.common.exception.CustomException;
import com.chengcang.common.exception.ErrorCode;
import com.chengcang.common.redis.RedisKeys;
import com.chengcang.common.redis.RedisUtils;
import com.chengcang.common.utils.IpUtils;
import com.chengcang.common.utils.PasswordUtils;
import com.chengcang.common.utils.Result;
import com.chengcang.common.validator.AssertUtils;
import com.chengcang.common.validator.ValidatorUtils;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

/**
 * 登录接口
 *
 * @author zhanli
 */
@Slf4j
@RestController
@RequestMapping("/")
@Api(tags = "登录接口")
public class ApiLoginController {
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysUserTenantService sysUserTenantService;
    @Autowired
    private SysUserTokenService sysUserTokenService;
    @Autowired
    private CaptchaService captchaService;
    @Autowired
    private SysLogLoginService sysLogLoginService;
    @Autowired
    private RedisUtils redisUtils;

    /**
     * Local Cache  5分钟过期
     */
    Cache<String, String> localCache = CacheBuilder.newBuilder().maximumSize(1000).expireAfterAccess(5, TimeUnit.MINUTES).build();

    @GetMapping("captcha")
    @ApiOperation(value = "验证码", produces = "application/octet-stream")
    @ApiImplicitParam(paramType = "query", dataType = "string", name = "uuid", required = true)
    public void captcha(HttpServletResponse response, String uuid) throws IOException {
        //uuid不能为空
        AssertUtils.isBlank(uuid, ErrorCode.IDENTIFIER_NOT_NULL);

        //生成验证码
        captchaService.create(response, uuid);
    }

    @PostMapping("login")
    @ApiOperation(value = "登录")
    public Result login(HttpServletRequest request, @RequestBody LoginDTO login) {
        //效验数据
        ValidatorUtils.validateEntity(login);
        //验证码是否正确
        /*   boolean flag = captchaService.validate(login.getUuid(), login.getCaptcha());
        if (!flag) {
            return new Result().error(ErrorCode.CAPTCHA_ERROR);
        }*/
        //查询租户，判断是否多个租户
        SysUserDTO user = sysUserService.getByUsername(login.getUsername());
        if (Objects.isNull(user)) {
            throw new CustomException("用户名或密码错误！");
        }
        if (user.getStatus().equals(1)) {
            throw new CustomException("用户名或密码错误！");
        }
        SysLogLoginEntity log = new SysLogLoginEntity();
        log.setOperation(LoginOperationEnum.LOGIN.value());
        log.setCreateDate(new Date());
        log.setIp(IpUtils.getIpAddr(request));
        log.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
        //用户不存在
        if (user == null) {
            log.setStatus(LoginStatusEnum.FAIL.value());
            log.setCreatorName(login.getUsername());
            sysLogLoginService.save(log);

            throw new CustomException(ErrorCode.ACCOUNT_PASSWORD_ERROR);
        }
        //密码错误
        if (!PasswordUtils.matches(login.getPassword(), user.getPassword())) {
            log.setStatus(LoginStatusEnum.FAIL.value());
            log.setCreator(user.getId());
            log.setCreatorName(user.getUsername());
            sysLogLoginService.save(log);

            throw new CustomException(ErrorCode.ACCOUNT_PASSWORD_ERROR);
        }
        //账号停用
        if (user.getStatus() == UserTenantStatusEnum.DISABLE.value()) {
            log.setStatus(LoginStatusEnum.LOCK.value());
            log.setCreator(user.getId());
            log.setCreatorName(user.getUsername());
            sysLogLoginService.save(log);

            throw new CustomException(ErrorCode.ACCOUNT_DISABLE);
        }
        //登录成功
        log.setLoginSource("网站");
        log.setStatus(LoginStatusEnum.SUCCESS.value());
        log.setCreator(user.getId());
        log.setCreatorName(user.getUsername());
        // 设置默认租户ID
        log.setUserId(user.getId());
        log.setTenantId(user.getDefaultTenantId());
        sysLogLoginService.save(log);
        return sysUserTokenService.createToken(user.getId(), user.getDefaultTenantId());
    }

    @Login
    @GetMapping("switch")
    @ApiOperation("切换租户")
    public Result switchTenant(Long tenantId) {
        List<UserTenant> userTenantList = sysUserTenantService.getUserTenantList(UserHolder.getUserId());

        boolean contains = userTenantList.stream().map(UserTenant::getTenantId).anyMatch(o -> Objects.equals(o, tenantId));
        if (contains) {
            log.info("切换租户记录，原默认租户: {}, 切换的tenantId:{}", UserHolder.getUser().getDefaultTenantId(), tenantId);
            // 校验此租户是否为当前登录用户所拥有，否则不允许切换
            if (!CollectionUtils.isEmpty(userTenantList)) {
                UserTenant userTenantEntity = userTenantList.stream().filter(o -> Objects.equals(tenantId, o.getTenantId()) && o.getUserType() == 1).findFirst().orElse(null);
                Optional.ofNullable(userTenantEntity).ifPresent(o -> UserHolder.switchTenant(userTenantEntity.getTenantId(), userTenantEntity.getUserType(),userTenantEntity.getTenantType()));
            }
            // 切换的时候更改在线状态
            Optional.ofNullable(UserHolder.getUser().getDefaultTenantId()).ifPresent(o -> {
                String userKey = RedisConstant.SYS_USER + UserHolder.getUserId();
                Long expire = redisUtils.getExpire(userKey);
                Optional.ofNullable(expire).ifPresent(o1 -> redisUtils.set(userKey, tenantId, o1));
            });
            return new Result().ok(UserHolder.getUser());
        } else {
            return new Result().error("用户不属于该客户，不允许切换");
        }

    }

    @Login
    @PostMapping("logout")
    @ApiOperation(value = "退出")
    public Result logout(HttpServletRequest request) {
        SysUserDTO user = UserHolder.getUser();
        //退出
        sysUserTokenService.logout(user.getId());
        return new Result();
    }

    @Login
    @PutMapping("password")
    @ApiOperation("修改密码")
    public Result password(@RequestBody PasswordDTO dto) {
        //效验数据
        ValidatorUtils.validateEntity(dto);

        SysUserDTO user = UserHolder.getUser();

        //原密码不正确
        if (!PasswordUtils.matches(dto.getPassword(), user.getPassword())) {
            return new Result().error(ErrorCode.PASSWORD_ERROR);
        }

        sysUserService.updatePassword(user.getId(), dto.getNewPassword());

        return new Result();
    }

    /**
     * 图形验证码防刷
     * @param code
     * @param uuid
     * @return
     * @throws IOException
     */
    @GetMapping("prevent")
    @ApiOperation("短信接口防刷")
    public Result prevent(@RequestParam String code,@RequestParam String uuid) throws IOException {
        if (StringUtils.isBlank(code)){
            throw new CustomException("请先输入验证码");
        }
        //uuid不能为空
        AssertUtils.isBlank(uuid, ErrorCode.IDENTIFIER_NOT_NULL);
        //验证验证码
        Object captcha = redisUtils.get(RedisKeys.getCaptchaKey(uuid));
        if (!code.equals(captcha.toString())) {
            throw new CustomException("输入的验证码有误");
        }
        return new Result();
    }


//    @RateLimit(number = 1,cycle = 300,msg = "访问的太频繁了")
    @GetMapping("sendCode")
    @ApiOperation("发送验证码")
    public Result sendCode(@RequestParam String mobile,@RequestParam String uuid) throws ClientException, IOException {

        //判空校验
        if (StringUtils.isBlank(mobile)) {
            throw new CustomException("手机号不能为空");
        }
        //手机号格式校验
        if (!Pattern.matches("^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\\d{8}$", mobile)) {
            throw new CustomException("手机号格式不正确");
        }
        //看是否被占用
        SysUserDTO user = sysUserService.getByMobile(mobile);
        if (user != null) {
            throw new CustomException("该手机号码已被占用");
        }

        //uuid作为凭证，验证是否是先生成了图片验证码
        if (redisUtils.get(RedisKeys.getCaptchaKey(uuid)) == null){
            throw new CustomException("请先通过验证");
        } else {
            //消耗掉凭证
            redisUtils.delete(RedisKeys.getCaptchaKey(uuid));
        }
        //String code = RandomUtil.randomNumbers(6); //验证码  6位数
        String code = "666666";
        //aliyun发送短信
        //SendSmsResponse sMsResponse = SmsUtil.sendVerifyCode(mobile, code, "SMS_269220011");
        //if (sMsResponse.getCode() != null && sMsResponse.getCode().equals("OK")){
            //将验证码和对应号码存入redis
            redisUtils.set(RedisKeys.getCaptchaKey(mobile),code,300);
            return new Result();
       // } else {
           // return new Result().error("验证码发送失败");
        //}
    }

    @GetMapping("forgetPwd")
    @ApiOperation("忘记密码")
    public Result forgetpwd(@RequestBody MobileCodeDTO dto) throws ClientException {
        //校验数据
        ValidatorUtils.validateEntity(dto);
        //手机号格式校验
        if(!Pattern.matches("^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\\d{8}$",dto.getMobile())){
            throw new CustomException("手机号格式不正确");
        }
        //根据电话查询验证码是否存在
        Object code = redisUtils.get(RedisKeys.getCaptchaKey(dto.getMobile()));
        if (!dto.getCaptcha().equals(code.toString())) {
            throw new CustomException(ErrorCode.CAPTCHA_ERROR);
        }
        //判断用户是否存在
        SysUserDTO user = sysUserService.getByMobile(dto.getMobile());
        if (user == null) {
            throw new CustomException("该手机号码不存在");
        }

        return new Result();
    }

    @GetMapping("setNewPwd")
    @ApiOperation("设置新密码")
    public Result setNewPwd(@RequestBody RsetPwdDTO dto) {
        //数据校验
        ValidatorUtils.validateEntity(dto);
        if (!dto.getFirstPwd().equals(dto.getSecondPwd())){
            throw new CustomException("两次输入的密码不一致");
        }
        SysUserDTO sysUserDTO = sysUserService.getByMobile(dto.getMobile());
        sysUserService.updatePassword(sysUserDTO.getId(),PasswordUtils.encode(dto.getFirstPwd()));
        return new Result();
    }


}